package commons.ihm;

import commons.data.I_Data;
import commons.drawing.I_Drawable;
import commons.drawing.UtilsDrawing.DrawQuality;
import commons.drawing.couche.I_Couche;
import commons.ihm.ParametresAffichageCarto.TypeAffichage;
import commons.spatialindex.I_SpatialIndexable;
import commons.utils.UtilsCalcul;
import commons.utils.UtilsTime;
import commons.utils.primitive_geom.Point_d;
import commons.utils.primitive_geom.Rect_d;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;


public abstract class A_PanelCartoTocTools extends javax.swing.JPanel implements TreeSelectionListener {

	// Le panel TOC dépend du type de PanelCartoTocTools
	abstract protected void createPanel_TOC();

	protected I_Data data;
	
	protected PanelCarto panelCarto;
	protected A_PanelTOC panelTOC;

	public void setTypeAffichage(TypeAffichage typeAffichage) {panelCarto.setTypeAffichage(typeAffichage);}

	private double echelleCarteCourante;

    public A_PanelCartoTocTools() {
        initComponents();

		combo_EchelleVisu.getModel().setSelectedItem("");
		combo_EchelleVisu.setEnabled(false);

		// création des panels Carto et TOC : on les ajoute à la main plutot que via l'interface du GUI Builder, c'est plus simple
		panelCarto = new PanelCarto(this);
		createPanel_TOC(); // Le panel TOC dépend si on est en generalisation anno ou lignes-sites

		tree_Search.addTreeSelectionListener(this);
		tree_Search.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

		// On insere les panel aux emplacements prévus
		panel_ContainerCARTO.add(panelCarto, java.awt.BorderLayout.CENTER);
		panel_ContainerTOC.add(panelTOC, java.awt.BorderLayout.CENTER);

		updateQuality();

		repaintCarto();
	}

	// l'objet data depend si on est dans un PanelCartoTocTools pour les lignes/sites ou pour les annotations
	public void setData (I_Data data) {
		this.data = data;
		if (data==null) return;

		combo_EchelleVisu.setEnabled(true);

		// On remplit la TOC avec des couches construites à partir du Data
		panelTOC.setData(data);

		// Zoom sur l'ensemble du data
		Rect_d rectEmprise = data.getRectEmprise();
		rectEmprise.expand(1.2);
		panelCarto.setEmpriseDataToDisplay(rectEmprise);

		panelCarto.repaint();
	}

	// regle le niveau de qualité d'affichage suivant le statut de 'toggle_Quality'
	private void updateQuality() {
		if (toggle_Quality.isSelected()) {
			toggle_Quality.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/icons/AffichageRapide_32.png")));
			panelCarto.setDrawQuality(DrawQuality.FAST);
		}  else {
			toggle_Quality.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/icons/AffichageQualite_32.png")));
			panelCarto.setDrawQuality(DrawQuality.PRECISE);
		}
	}

	//**************************************************************************
	//  LOGIQUE  PanelCartoTOCTools <-> PanelCarto
	//**************************************************************************

	public void repaintCarto() {
		panelCarto.repaint();
	}

	// appelé par la fenetre de gestion de selection
	public void repaintOnlySelection() {
		panelCarto.repaintOnlySelection();
	}

	// Ajuste le zoom pour visualiser l'étendu des données
	public void zoomEmpriseData() {
	    panelCarto.zoomEmpriseData();
		repaintCarto();
	}


	public void setEchelleCarteCourante (double echelleCarteCourante_inv) {
		this.echelleCarteCourante = 1.0 / echelleCarteCourante_inv;
		tf_EchelleCarteCourante.setText("" + UtilsCalcul.round(echelleCarteCourante_inv, 2));

		// On raffraichit l'indication de % ZoomPapier
		// (rq. : l'échelle de visu, elle, n'a pas changé)
//		updateEchelleVisuaAndZoomPapier (panel_Carto_.pac.getEchelleVisualisation());
	}

	// Le panelCarto demande a son pere la liste des couches à dessiner : c'est le panelTOC qui fournit cette liste
	protected ArrayList<I_Couche> getVisibleCouches() {
		return panelTOC.getVisibleCouches();
	}

	/**
	 * Affiche les coordonnées x,y fournies dans les 2 text fields prévus pour.
	 * Appelé par le panelCarto quand la souris bouge.
	 */
	protected void showXY (double x_m, double y_m) {
		tf_X.setText(""+UtilsCalcul.round(x_m, 2));
		tf_Y.setText(""+UtilsCalcul.round(y_m, 2));
	}
	
	protected void showFact_DistSourisNode_RayonNode (double fact) {
		tf_FactDistCentre.setText(""+UtilsCalcul.round(fact, 2));
	}

	// Appelé par le panelCarto dès que la souris est relachée
	protected void panelCartoHasReleasedMouse(int xClic, int yClic, int xRelease, int yRelease) {
		if (panelCarto.isModeZoomPlus()) {
			stopModeZoomPlus();
			// On zoom sur l'étendue du rectangle dessiné
			int xMin = Math.min(xClic, xRelease);
			int xMax = Math.max(xClic, xRelease);
			int yMin = Math.min(yClic, yRelease);
			int yMax = Math.max(yClic, yRelease);

			panelCarto.zoomThisEmprise_px(new Rect_d (xMin, yMin, xMax, yMax));
		}
	}

	// Notamment appelé par le panelCarto si le mode zoom doit être annulé (si molette souris, ou clic dans TOC etc.)
	protected void stopModeZoomPlus() {
		toggle_ZoomPlus.setSelected(false);
		panelCarto.setModeZoomPlus(false);
	}

	// Appelé par le panelCarto dès que son zoom a été modifié, afin que le panel
	// CartoTocTool puisse mettre à jour les infos d'échelle et de zoom
	protected void panelCartoAskForNewZoom(double currentEchelleVisu) {
		updateEchelleVisuAndZoomPapier (currentEchelleVisu);
	}

	// Met a jour les indications présentées sous forme de combo
	protected void updateEchelleVisuAndZoomPapier (double currentEchelleVisu) {
		combo_EchelleVisu.getModel().setSelectedItem("" + UtilsCalcul.round(1.0/ currentEchelleVisu, 2));
		if (echelleCarteCourante ==0) {
			tf_ZoomPapier.setText("");
		} else {
			tf_ZoomPapier.setText("" + ( (int) (100.0 * currentEchelleVisu / echelleCarteCourante)) );
		}
	}


	//**************************************************************************
	//***** Gestion de la recherche ********************************************
	//**************************************************************************

	// recherche des objets visibles correspondant au pattern entré par l'utilisateur
	private void search() {
//UtilsTime.startTimer("search");
		if (tf_PatternSearch.getText().trim().length()==0)
			// aucun critère de recherche
			return;

		// suppression de toutes les anciennes sélection
		clearSelectionAndHighlight();

		// On lance une sélection via Pattern dans toutes les couches affichées
		String pattern = tf_PatternSearch.getText().trim().toUpperCase();
		pattern = pattern.replaceAll("\\.", "\\\\."); // attention , le "." est un caractère spécial !, à remplacer par "\."
		pattern = pattern.replaceAll("\\*", ".*");  //
		pattern = ".*" + pattern + ".*";

		for (I_Couche couche : panelTOC.getVisibleCouches())
			couche.select(pattern);

		updateTreeWithSelection();
//UtilsTime.stopTimer("search");
//System.out.println(UtilsTime.getStringDuree("search"));

		repaintOnlySelection();
	}

	public void clearSelectionAndHighlight() {
		if (panelTOC == null) return; // peut arriver lors d'appels tres tot lors la construction de l'IHM
		if (panelTOC.getAllCouches() == null) return;

		for (I_Couche couche : panelTOC.getAllCouches())
			couche.clearSelection();
		panelCarto.setObjetcHighLighted(null);
		updateTreeWithSelection();
	}

	//**************************************************************************
	//***** Gestion de la sélection ********************************************
	//**************************************************************************

	public void selectFromXY(double xMouse_m, double yMouse_m, double distSearch_m) {
		// On demande à chaque couche de calculer la sélection correspondant au point du clic
		ArrayList<I_Couche> vCouche = getVisibleCouches();
		for (I_Couche couche : vCouche)
			couche.select(new Point_d(xMouse_m, yMouse_m), distSearch_m);

		updateTreeWithSelection();

		repaintOnlySelection();
	}

	// Selection à partir d'une liste d'objets
	public void selectFromListObject(ArrayList<I_Drawable> vObj) {
		// On demande à chaque couche de déterminer si elle contient des objets de vObj
		ArrayList<I_Couche> vCouche = getVisibleCouches();
		for (I_Couche couche : vCouche)
			couche.select(vObj);

		updateTreeWithSelection();

		repaintOnlySelection();
	}


	// Met à jour l'arbre avec la sélection présente dans les couches visibles
	private void updateTreeWithSelection() {
		if (panelTOC == null) return; // peut arriver lors d'appels tres tot lors la construction de l'IHM

		DefaultMutableTreeNode node_root = new DefaultMutableTreeNode("Résultats");
		ArrayList<I_Couche> vCouche = panelTOC.getVisibleCouches();

		for (int i=vCouche.size()-1; i>=0 ; i--) {
			I_Couche couche = vCouche.get(i);

			ArrayList<I_Drawable> vSelection = couche.getSelection();
			if (vSelection.isEmpty())
				continue;

			DefaultMutableTreeNode node_coucheName = new DefaultMutableTreeNode(couche.getName() + " (" + vSelection.size() + ")");

			for (I_Drawable o : vSelection) {
				DefaultMutableTreeNode node_objectName = new DefaultMutableTreeNode(o);
				node_coucheName.add(node_objectName);
			}
			node_root.add(node_coucheName);
		}

		tree_Search.setModel(new DefaultTreeModel(node_root));

		//on déplie l'ensemble des nodes
		for (int i=0; i<node_root.getChildCount() ; i++) {
			TreePath path = new TreePath (((DefaultMutableTreeNode)node_root.getChildAt(i)).getPath());
			tree_Search.expandPath(path);
		}

		// on sélectionne la première feuille (=le premier objet sélectionné)
		if (node_root.getChildCount()>0 && node_root.getChildAt(0).getChildCount()>0) {
			TreePath path = new TreePath (((DefaultMutableTreeNode) node_root.getChildAt(0).getChildAt(0) ).getPath());
			tree_Search.setSelectionPath(path);
		}
	}

	// Appelé lors d'un changement de sélection dans l'arbre de gestion des sélections ...
	@Override
	public void valueChanged(TreeSelectionEvent e) {
		//System.out.println("&&&&& SELECTION EVENT");
		DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree_Search.getLastSelectedPathComponent();
		if (node==null || !node.isLeaf()) {
			textArea_Details.setText("");
			panelCarto.setObjetcHighLighted(null);
			panelCarto.repaintOnlySelection();
		} else if (node.isLeaf()) {
			// Si c'est un node feuille, alors nécessairement c'est un I_Drawable,
			//  car on ne met pas dans l'arbre des node de type couche mais vide
			// petit test malgré tout ...
			if (node.getUserObject() instanceof I_Drawable) {
				I_Drawable o = (I_Drawable) node.getUserObject();
				textArea_Details.setText(o.getInfoDetaillee());
				textArea_Details.setCaretPosition(0);//on scrool au debut
				panelCarto.setObjetcHighLighted(o);
				panelCarto.repaintOnlySelection();
			}
// 05/02/13 pourquoi on doit calculer une force si selection d'une junction ? -> annulé
//			if (node.getUserObject() instanceof JunctionDER) {
//				((JunctionDER)node.getUserObject()).computeForcesRepuls(Data_ls.data_ls);
//			}
		}
	}

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jSplitPane3 = new javax.swing.JSplitPane();
        panel_ContainerTOC = new javax.swing.JPanel();
        jSplitPane1 = new javax.swing.JSplitPane();
        panel_Search = new javax.swing.JPanel();
        jSplitPane2 = new javax.swing.JSplitPane();
        jPanel1 = new javax.swing.JPanel();
        jLabel7 = new javax.swing.JLabel();
        tf_PatternSearch = new javax.swing.JTextField();
        btn_Search = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        tree_Search = new javax.swing.JTree();
        btn_ZoomSelection = new javax.swing.JButton();
        jPanel2 = new javax.swing.JPanel();
        jScrollPane4 = new javax.swing.JScrollPane();
        textArea_Details = new javax.swing.JTextArea();
        jLabel10 = new javax.swing.JLabel();
        panel_ContainerCARTO = new javax.swing.JPanel();
        panel_Tools = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        combo_EchelleVisu = new javax.swing.JComboBox();
        jLabel3 = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        toggle_ZoomPlus = new javax.swing.JToggleButton();
        button_ZoomAll = new javax.swing.JButton();
        toggle_Quality = new javax.swing.JToggleButton();
        jLabel5 = new javax.swing.JLabel();
        tf_EchelleCarteCourante = new javax.swing.JTextField();
        button_ZoomMoins = new javax.swing.JButton();
        jLabel2 = new javax.swing.JLabel();
        tf_X = new javax.swing.JTextField();
        jLabel6 = new javax.swing.JLabel();
        tf_Y = new javax.swing.JTextField();
        jLabel8 = new javax.swing.JLabel();
        jLabel9 = new javax.swing.JLabel();
        tf_ZoomPapier = new javax.swing.JTextField();
        jLabel11 = new javax.swing.JLabel();
        tf_FactDistCentre = new javax.swing.JTextField();

        jSplitPane3.setBorder(null);
        jSplitPane3.setDividerLocation(180);
        jSplitPane3.setContinuousLayout(true);

        panel_ContainerTOC.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(153, 153, 153)));
        panel_ContainerTOC.setLayout(new java.awt.BorderLayout());
        jSplitPane3.setLeftComponent(panel_ContainerTOC);

        jSplitPane1.setBorder(null);
        jSplitPane1.setContinuousLayout(true);

        panel_Search.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(153, 153, 153)));

        jSplitPane2.setDividerLocation(250);
        jSplitPane2.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        jSplitPane2.setContinuousLayout(true);

        jLabel7.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        jLabel7.setText("Recherche :");

        tf_PatternSearch.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
        tf_PatternSearch.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                tf_PatternSearchKeyPressed(evt);
            }
        });

        btn_Search.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/icons/FlecheDroiteGrise_16.png"))); // NOI18N
        btn_Search.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        btn_Search.setMargin(new java.awt.Insets(2, 5, 2, 5));
        btn_Search.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btn_SearchActionPerformed(evt);
            }
        });

        tree_Search.setModel(new DefaultTreeModel(null));
        tree_Search.setRootVisible(false);
        tree_Search.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                tree_SearchMousePressed(evt);
            }
        });
        tree_Search.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                tree_SearchKeyPressed(evt);
            }
        });
        jScrollPane1.setViewportView(tree_Search);

        btn_ZoomSelection.setText("Zoom sur sélection");
        btn_ZoomSelection.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        btn_ZoomSelection.setMargin(new java.awt.Insets(1, 4, 1, 4));
        btn_ZoomSelection.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btn_ZoomSelectionActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                        .addGap(8, 8, 8)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jScrollPane1)
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addComponent(jLabel7)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(tf_PatternSearch, javax.swing.GroupLayout.DEFAULT_SIZE, 108, Short.MAX_VALUE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(btn_Search, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(btn_ZoomSelection, javax.swing.GroupLayout.PREFERRED_SIZE, 99, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                    .addComponent(btn_Search, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(tf_PatternSearch, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel7))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 81, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(btn_ZoomSelection)
                .addContainerGap())
        );

        jSplitPane2.setTopComponent(jPanel1);

        textArea_Details.setColumns(20);
        textArea_Details.setFont(new java.awt.Font("Monospaced", 0, 10)); // NOI18N
        textArea_Details.setRows(5);
        jScrollPane4.setViewportView(textArea_Details);

        jLabel10.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        jLabel10.setText("Détails :");

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup()
                .addGap(8, 8, 8)
                .addComponent(jScrollPane4, javax.swing.GroupLayout.DEFAULT_SIZE, 210, Short.MAX_VALUE)
                .addContainerGap())
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel10)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addGap(6, 6, 6)
                .addComponent(jLabel10)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane4, javax.swing.GroupLayout.DEFAULT_SIZE, 539, Short.MAX_VALUE)
                .addContainerGap())
        );

        jSplitPane2.setRightComponent(jPanel2);

        javax.swing.GroupLayout panel_SearchLayout = new javax.swing.GroupLayout(panel_Search);
        panel_Search.setLayout(panel_SearchLayout);
        panel_SearchLayout.setHorizontalGroup(
            panel_SearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jSplitPane2, javax.swing.GroupLayout.Alignment.TRAILING)
        );
        panel_SearchLayout.setVerticalGroup(
            panel_SearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jSplitPane2)
        );

        jSplitPane1.setLeftComponent(panel_Search);

        panel_ContainerCARTO.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(153, 153, 153)));
        panel_ContainerCARTO.setLayout(new java.awt.BorderLayout());
        jSplitPane1.setRightComponent(panel_ContainerCARTO);

        jSplitPane3.setRightComponent(jSplitPane1);

        panel_Tools.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(153, 153, 153)));

        jLabel1.setText("Ech. de visu :");

        combo_EchelleVisu.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "5000", "10000", "25000", "50000", "100000", "250000", "500000", "1000000", "2000000", "5000000" }));
        combo_EchelleVisu.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
        combo_EchelleVisu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                combo_EchelleVisuActionPerformed(evt);
            }
        });

        jLabel3.setText("Zoom / papier :");

        jLabel4.setText("%");

        toggle_ZoomPlus.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/icons/ZoomZone_32.png"))); // NOI18N
        toggle_ZoomPlus.setToolTipText("Zoom sur une zone rectangulaire");
        toggle_ZoomPlus.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        toggle_ZoomPlus.setMargin(new java.awt.Insets(0, 0, 0, 0));
        toggle_ZoomPlus.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                toggle_ZoomPlusActionPerformed(evt);
            }
        });

        button_ZoomAll.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/icons/ZoomAll_32.png"))); // NOI18N
        button_ZoomAll.setToolTipText("Zoom sur l'ensemble des données");
        button_ZoomAll.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        button_ZoomAll.setMargin(new java.awt.Insets(0, 0, 0, 0));
        button_ZoomAll.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                button_ZoomAllActionPerformed(evt);
            }
        });

        toggle_Quality.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/icons/AffichageQualite_32.png"))); // NOI18N
        toggle_Quality.setToolTipText("Bascule entre affichage de qualité et rapide");
        toggle_Quality.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        toggle_Quality.setMargin(new java.awt.Insets(0, 0, 0, 0));
        toggle_Quality.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                toggle_QualityActionPerformed(evt);
            }
        });

        jLabel5.setText("Ech. carte :");

        tf_EchelleCarteCourante.setEditable(false);
        tf_EchelleCarteCourante.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));

        button_ZoomMoins.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/icons/ZoomOut_32.png"))); // NOI18N
        button_ZoomMoins.setToolTipText("Zoom arrière");
        button_ZoomMoins.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        button_ZoomMoins.setMargin(new java.awt.Insets(0, 0, 0, 0));
        button_ZoomMoins.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                button_ZoomMoinsActionPerformed(evt);
            }
        });

        jLabel2.setText("X :");

        tf_X.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));

        jLabel6.setText("Y :");

        tf_Y.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));

        jLabel8.setText("1 /");

        jLabel9.setText("1 /");

        tf_ZoomPapier.setEditable(false);
        tf_ZoomPapier.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));

        jLabel11.setText("k * rayon :");

        tf_FactDistCentre.setEditable(false);
        tf_FactDistCentre.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));

        javax.swing.GroupLayout panel_ToolsLayout = new javax.swing.GroupLayout(panel_Tools);
        panel_Tools.setLayout(panel_ToolsLayout);
        panel_ToolsLayout.setHorizontalGroup(
            panel_ToolsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(panel_ToolsLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(button_ZoomAll, javax.swing.GroupLayout.PREFERRED_SIZE, 43, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(toggle_ZoomPlus, javax.swing.GroupLayout.PREFERRED_SIZE, 39, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(button_ZoomMoins, javax.swing.GroupLayout.PREFERRED_SIZE, 47, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(toggle_Quality, javax.swing.GroupLayout.PREFERRED_SIZE, 41, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addGroup(panel_ToolsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addGroup(panel_ToolsLayout.createSequentialGroup()
                        .addComponent(jLabel2)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(tf_X))
                    .addGroup(panel_ToolsLayout.createSequentialGroup()
                        .addComponent(jLabel6)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(tf_Y, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addGap(33, 33, 33)
                .addComponent(jLabel5)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel9)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(tf_EchelleCarteCourante, javax.swing.GroupLayout.PREFERRED_SIZE, 84, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jLabel1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel8)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(combo_EchelleVisu, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jLabel3)
                .addGap(2, 2, 2)
                .addComponent(tf_ZoomPapier, javax.swing.GroupLayout.PREFERRED_SIZE, 51, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel4)
                .addGap(18, 18, 18)
                .addComponent(jLabel11)
                .addGap(2, 2, 2)
                .addComponent(tf_FactDistCentre, javax.swing.GroupLayout.PREFERRED_SIZE, 51, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );
        panel_ToolsLayout.setVerticalGroup(
            panel_ToolsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(panel_ToolsLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(panel_ToolsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(panel_ToolsLayout.createSequentialGroup()
                        .addGroup(panel_ToolsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(panel_ToolsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(jLabel11)
                                .addComponent(tf_FactDistCentre, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                            .addGroup(panel_ToolsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(jLabel2)
                                .addComponent(tf_X, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(jLabel5)
                                .addComponent(jLabel9)
                                .addComponent(tf_EchelleCarteCourante, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(jLabel1)
                                .addComponent(jLabel8)
                                .addComponent(combo_EchelleVisu, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(jLabel3)
                                .addComponent(tf_ZoomPapier, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(jLabel4)))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(panel_ToolsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(jLabel6)
                            .addComponent(tf_Y, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                    .addGroup(panel_ToolsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                        .addComponent(button_ZoomMoins, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(toggle_ZoomPlus, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(button_ZoomAll, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(toggle_Quality)))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(panel_Tools, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(jSplitPane3)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(panel_Tools, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jSplitPane3))
        );
    }// </editor-fold>//GEN-END:initComponents

	private void combo_EchelleVisuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_combo_EchelleVisuActionPerformed
		//System.out.println("COMBO ECHELLE VISU");
		String echelle_inv = (String) combo_EchelleVisu.getSelectedItem();
		if (echelle_inv.equals("")) return;
		double echelle = 1.0 / Double.parseDouble(echelle_inv);

		// en retour, cette fonction va appeler panelCartoHasModifiedZoom(), qui va mettre à jour le % papier
		// TODO_KO ALGO euh non ... ca ne fonctionne pas bien
		panelCarto.setEchelleVisu(echelle);
}//GEN-LAST:event_combo_EchelleVisuActionPerformed

	private void toggle_ZoomPlusActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_toggle_ZoomPlusActionPerformed
		if (toggle_ZoomPlus.isSelected()) {
			panelCarto.setModeZoomPlus(true);
		} else {
			panelCarto.setModeZoomPlus(false);
		}
}//GEN-LAST:event_toggle_ZoomPlusActionPerformed

	private void button_ZoomAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_button_ZoomAllActionPerformed
		zoomEmpriseData();
}//GEN-LAST:event_button_ZoomAllActionPerformed

	private void toggle_QualityActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_toggle_QualityActionPerformed
		updateQuality();
		repaintCarto();
}//GEN-LAST:event_toggle_QualityActionPerformed

	private void button_ZoomMoinsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_button_ZoomMoinsActionPerformed
		panelCarto.modifyZoomByFactor(0.6);
}//GEN-LAST:event_button_ZoomMoinsActionPerformed

	private void tf_PatternSearchKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_tf_PatternSearchKeyPressed

		// Touche ENTER dans la zone de recherche ?
		if (evt.getKeyCode() == KeyEvent.VK_ENTER) {
			search();
			tree_Search.grabFocus();
		}
	}//GEN-LAST:event_tf_PatternSearchKeyPressed

	private void tree_SearchMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tree_SearchMousePressed
		// Gestion double clic dans le tree
		if(evt.getClickCount() == 2)
			zoomSurObjectSelectedInTreeSearch();
	}//GEN-LAST:event_tree_SearchMousePressed

	private void zoomSurObjectSelectedInTreeSearch() {
		int[] rowsSelected = tree_Search.getSelectionRows();
		if (rowsSelected.length == 0)
			return; // pas de sélection

		int fstRowSelected = rowsSelected[0];

		DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree_Search.getLastSelectedPathComponent();
		if (node!=null && node.isLeaf()) {
			// Si c'est un node feuille, alors nécessairement c'est un I_SpatialIndexable,
			//  car on ne met pas dans l'arbre des node de type couche mais vide
			// mais petit test au cas ou
			if (node.getUserObject() instanceof I_SpatialIndexable) {
				I_SpatialIndexable o = (I_SpatialIndexable) node.getUserObject();
				panelCarto.zoomThisObject(o);
				panelCarto.repaint();
			}
		}

	}
	
	private void btn_SearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btn_SearchActionPerformed
		search();
		tree_Search.grabFocus();
	}//GEN-LAST:event_btn_SearchActionPerformed

	private void btn_ZoomSelectionActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btn_ZoomSelectionActionPerformed
		Rect_d rectEmpriseSelection=null;
		// On zoom sur l'ensemble des objets sélectionnés et visibles
		ArrayList<I_Couche> vCouche = panelTOC.getVisibleCouches();
		for (I_Couche couche : vCouche) {
			ArrayList<I_Drawable> vSelection = couche.getSelection();
			if (vSelection.isEmpty()) continue;

			for (I_Drawable o : vSelection) {
				if (!(o instanceof I_SpatialIndexable)) continue; // on ne peut zommer que sur des I_SpatialIndexable
				I_SpatialIndexable si = (I_SpatialIndexable) o;

				if (rectEmpriseSelection==null)
					// pour le 1er objet, on part directment de son emprise, car un extend() depuis un new Rect_d, va conserver (0,0) dans l'emprise !
					rectEmpriseSelection = si.getRectEmprise().getCopy();
				else
					rectEmpriseSelection.extendToRect(si.getRectEmprise());
			}
		}
		if (rectEmpriseSelection!=null)
			rectEmpriseSelection.expand(1.1);

		panelCarto.zoomThisEmprise(rectEmpriseSelection);
	}//GEN-LAST:event_btn_ZoomSelectionActionPerformed

    private void tree_SearchKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_tree_SearchKeyPressed
        if (evt.getKeyCode() == KeyEvent.VK_ENTER)
			zoomSurObjectSelectedInTreeSearch();
    }//GEN-LAST:event_tree_SearchKeyPressed



    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btn_Search;
    private javax.swing.JButton btn_ZoomSelection;
    private javax.swing.JButton button_ZoomAll;
    private javax.swing.JButton button_ZoomMoins;
    private javax.swing.JComboBox combo_EchelleVisu;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel10;
    private javax.swing.JLabel jLabel11;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JLabel jLabel9;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane4;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JSplitPane jSplitPane2;
    private javax.swing.JSplitPane jSplitPane3;
    private javax.swing.JPanel panel_ContainerCARTO;
    private javax.swing.JPanel panel_ContainerTOC;
    private javax.swing.JPanel panel_Search;
    private javax.swing.JPanel panel_Tools;
    private javax.swing.JTextArea textArea_Details;
    private javax.swing.JTextField tf_EchelleCarteCourante;
    private javax.swing.JTextField tf_FactDistCentre;
    private javax.swing.JTextField tf_PatternSearch;
    private javax.swing.JTextField tf_X;
    private javax.swing.JTextField tf_Y;
    private javax.swing.JTextField tf_ZoomPapier;
    private javax.swing.JToggleButton toggle_Quality;
    private javax.swing.JToggleButton toggle_ZoomPlus;
    private javax.swing.JTree tree_Search;
    // End of variables declaration//GEN-END:variables

}
